﻿using Basic.Repository.Abstract.Transactions;

namespace Basic.Repository.SqlSugar.UnitOfWork;

public class UnitOfWorkManage : IUnitOfWorkManage
{
    private readonly ILogger<UnitOfWorkManage> _logger;
    private readonly ISqlSugarClient _sqlSugarClient;

    private int _tranCount;
    public int TranCount => _tranCount;
    public readonly ConcurrentStack<string> TranStack = new();
    public IDisposable Connection => _sqlSugarClient;

    public UnitOfWorkManage(ILogger<UnitOfWorkManage> logger, ISqlSugarClient sqlSugarClient)
    {
        _logger = logger;
        _sqlSugarClient = sqlSugarClient;
    }

    /// <summary>
    /// 获取DB，保证唯一性
    /// </summary>
    /// <returns></returns>
    public SqlSugarScope GetDbClient()
    {
        // 必须要as，后边会用到切换数据库操作
        return _sqlSugarClient as SqlSugarScope;
    }

    public void BeginTran()
    {
        GetDbClient().BeginTran();
        _tranCount = Interlocked.Increment(ref _tranCount);
    }

    public void BeginTran(MethodInfo method)
    {
        lock (this)
        {
            GetDbClient().BeginTran();
            TranStack.Push(method.GetFullName());
            _tranCount = TranStack.Count;
        }
    }

    public void CommitTran()
    {
        try
        {
            GetDbClient().CommitTran();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            GetDbClient().RollbackTran();
        }
        _tranCount = Interlocked.Decrement(ref _tranCount);
    }

    public void CommitTran(MethodInfo method)
    {
        lock (this)
        {
            string result = "";
            while (!TranStack.IsEmpty && !TranStack.TryPeek(out result))
                Thread.Sleep(1);

            if (result == method.GetFullName())
            {
                try
                {
                    GetDbClient().CommitTran();

                    _logger.LogDebug($"Commit Transaction");
                    Console.WriteLine($"Commit Transaction");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    GetDbClient().RollbackTran();
                    _logger.LogDebug($"Commit Error , Rollback Transaction");
                }
                finally
                {
                    while (!TranStack.TryPop(out _))
                    {
                        Thread.Sleep(1);
                    }

                    _tranCount = TranStack.Count;
                }
            }
        }
    }

    public void RollbackTran()
    {
        GetDbClient().RollbackTran();
        _tranCount = Interlocked.Decrement(ref _tranCount);
    }

    public void RollbackTran(MethodInfo method)
    {
        lock (this)
        {
            string result = null;
            while (!TranStack.IsEmpty && !TranStack.TryPeek(out result))
                Thread.Sleep(1);

            if (result == method.GetFullName())
            {
                GetDbClient().RollbackTran();
                _logger.LogDebug($"Rollback Transaction");
                Console.WriteLine($"Rollback Transaction");
                while (!TranStack.TryPop(out _))
                    Thread.Sleep(1);

                _tranCount = TranStack.Count;
            }
        }
    }

}